package utwente.hmi.touchmol.elements;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

/**
 * The screenshot panel or bookmark panel shows the bookmarks made by the user.
 * @author FikkertFW, adapted by Jeroen Logtenberg.
 */
public class ScreenshotPanel extends JPanel {
	private static final long serialVersionUID = -621308129258328061L;
	public final static boolean DEBUG = false;

	private LinkedList<Screenshot> screenshots;
	private int activeScreenshot = -1;
	private int width;
	private int height;

	public ScreenshotPanel(int myWidth, int myHeight) {
		width = myWidth;
		height = myHeight;
		setPreferredSize(new Dimension(myWidth, myHeight));
		screenshots = new LinkedList<Screenshot>();
		
		setVisible(true);
	}

	/**
	 * Searches screenshots for image
	 * 
	 * @param newImage
	 * @return
	 */
	protected boolean contains(BufferedImage newImage) {
		for (Screenshot shot : screenshots)
			if (shot.screen.equals(newImage))
				return true;
		return false;
	}

	public Screenshot getPreviousScreenshot() {
		if (screenshots.size() == 0)
			return null;
		activeScreenshot--;
		if (activeScreenshot < 0)
			activeScreenshot = screenshots.size() - 1;
		setActiveScreenshot(activeScreenshot);
		return screenshots.get(activeScreenshot);
	}

	public Screenshot getNextScreenshot() {
		if (screenshots.size() == 0)
			return null;
		activeScreenshot++;
		if (activeScreenshot == screenshots.size())
			activeScreenshot = 0;
		setActiveScreenshot(activeScreenshot);
		return screenshots.get(activeScreenshot);
	}

	public Screenshot getScreenshot(int index) {
		assert (screenshots.size() > 0);
		assert (screenshots.size() > index - 1);
		return screenshots.get(index);
	}

	public Screenshot getLastScreenshot() {
		assert (screenshots.size() > 0);
		return screenshots.getLast();
	}

	public Screenshot getFirstScreenshot() {
		assert (screenshots.size() > 0);
		return screenshots.getFirst();
	}
	
	public LinkedList<Screenshot> getScreenshots(){
		return screenshots;
	}

	/**
	 * Adds screenshot to canvas
	 * @author LogtenbergJD (screenshot placement)
	 * @param newImage
	 * @return indexed position of added image
	 * @return -1 when already exists
	 */
	public int addScreenshot(BufferedImage newImage, String newScript,
			PropertyChangeListener myListener, int zoomValue, Point center) {
		if (contains(newImage)) {
			return -1;
		} else {
			Screenshot shot = new Screenshot(newImage, screenshots.size(),
					newScript);
			//to calculate the correct x and y for image placement, substract 
			//half the width/height of the thumbnail from the center locations.
			//Substract another 3 for border size. 
			shot.x = center.x - 3 - (int)(newImage.getWidth()*shot.width/2);
			shot.y = center.y - 3 - (int)(newImage.getHeight()*shot.height/2);
			shot.canvas = this;
			shot.zoom = zoomValue;

			shot.pcs.addPropertyChangeListener(myListener);
			addMouseListener(shot);
			addMouseMotionListener(shot);
			
			screenshots.addLast(shot);
			setActiveScreenshot(screenshots.size() - 1);
			// repaint();

			return screenshots.size() - 1;
		}
	}

	void moveActiveScreenshot(double x, double y) {
		if (screenshots.size() == 0)
			return;
		else if (activeScreenshot < 0)
			activeScreenshot = 0;
		Screenshot shot = screenshots.get(activeScreenshot);
		shot.x += x;
		shot.y += y;
		// and make sure that the screenshot does not "fall off the canvas"
		if (shot.x < 0)
			shot.x = 0;
		if (shot.y < 0)
			shot.y = 0;
		if (shot.x > width - shot.screen.getWidth() * shot.width)
			shot.x = (int) (width - shot.screen.getWidth() * shot.width);
		if (shot.y > height - shot.screen.getHeight() * shot.height)
			shot.y = (int) (height - shot.screen.getHeight() * shot.height);
		repaint();
	}

	void setOnTop(Screenshot shot) {
		if (shot == null) {
			activeScreenshot = -1;
		} else {
			activeScreenshot = screenshots.indexOf(shot);
			Screenshot backup = shot;
			if (onTop(shot) && !screenshots.getLast().equals(shot)) {
				screenshots.remove(shot);
				screenshots.addLast(backup);
			}
		}
	}

	boolean onTop(Screenshot shot) {
		return activeScreenshot == screenshots.indexOf(shot)
				|| activeScreenshot == -1;
	}

	/**
	 * Removes screenshot from canvas
	 * 
	 * @param index
	 * @return true if removed succesfully
	 */
	public boolean removeScreenshot(Screenshot shot) {
		try {
			removeMouseListener(shot);
			removeMouseMotionListener(shot);
			return screenshots.remove(shot);
		} catch (IndexOutOfBoundsException exc) {
			Logger.getLogger(ScreenshotPanel.class.getName()).log(Level.SEVERE,
					"Could not make screenshot", exc);
			return false;
		}
	}

	/**
	 * This method checks if the bookmark panel is touched at a certain location.
	 * @param location The point on the screen where the touch has occurred.
	 * @return If the touch has occurred inside the panel.
	 */
	public boolean panelTouched(Point location){
		Rectangle r = this.getBounds();
		Point p = this.getLocationOnScreen();
		r.setLocation(p);
		return r.contains(location);
	}
	
	@Override
	public void paint(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		
		g2.setColor(Color.BLACK);
		g2.fillRect(0, 0, getWidth(), getHeight());

		
		
		// display screenshots
		for (final Screenshot shot : screenshots) {
			shot.transform = new AffineTransform(shot.width, 0.0, 0.0,
					shot.height, shot.x, shot.y);
			shot.transform.rotate(shot.rotation);
			g2.drawImage(shot.screen, shot.transform, null);
			if (shot.isActive) {
				g2.setColor(Color.RED);
				g2.setStroke(new BasicStroke(3.0f));
				g2.drawRect(shot.x, shot.y,
						(int) (shot.screen.getWidth() * shot.width),
						(int) (shot.screen.getHeight() * shot.height));
			}
		}
		
		// display logo
		Image logo = loadLogo("res/logohmi-1040x601.gif");
		AffineTransform at = new AffineTransform();
		//scaling is already done in loadLogo(), all we need to do is translate.
		at.translate(width/4, height-logo.getHeight(null)- 10);
		g2.drawImage(logo, at, null);
		
		g2.dispose();
	}

	private void setActiveScreenshot(int myActiveScreenshot) {
		activeScreenshot = myActiveScreenshot;
		Screenshot active = screenshots.get(activeScreenshot);
		for (final Screenshot shot : screenshots)
			shot.isActive = shot == active;
		repaint();
	}

	private Image loadLogo(String ref) {  
		BufferedImage buflogo = null;
		Image logo = null;
		try {  
			buflogo = ImageIO.read(new File(ref));
			logo = buflogo.getScaledInstance(width/2, -1, Image.SCALE_SMOOTH);
		} catch (Exception e) {  
			e.printStackTrace();  
		}  
		return logo;  
	}
}
